package org.zecontech.extraplus.datagen.levelgen;

import net.minecraft.core.Holder;
import net.minecraft.core.HolderGetter;
import net.minecraft.core.registries.Registries;
import net.minecraft.data.worldgen.BootstrapContext;
import net.minecraft.data.worldgen.features.TreeFeatures;
import net.minecraft.data.worldgen.placement.PlacementUtils;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.levelgen.VerticalAnchor;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
import net.minecraft.world.level.levelgen.placement.BiomeFilter;
import net.minecraft.world.level.levelgen.placement.CountPlacement;
import net.minecraft.world.level.levelgen.placement.HeightRangePlacement;
import net.minecraft.world.level.levelgen.placement.InSquarePlacement;
import net.minecraft.world.level.levelgen.placement.PlacedFeature;
import net.minecraft.world.level.levelgen.placement.PlacementModifier;
import net.minecraft.world.level.levelgen.placement.RarityFilter;
import org.zecontech.extraplus.init.ModBlocks;
import org.zecontech.extraplus.util.Helpers;

import java.util.List;

/**
 * 模组placed feature数据生成提供者
 */
public class ModPlacedFeatureProvider {

    public static final ResourceKey<PlacedFeature> ORE_RUBY=
            register("ore_ruby");
    public static final ResourceKey<PlacedFeature> ORE_RUBY_LOWER =
            register("ore_ruby_lower");
    public static final ResourceKey<PlacedFeature> ORE_AMBER=
            register("ore_amber");
    public static final ResourceKey<PlacedFeature> ORE_AMBER_LOWER =
            register("ore_amber_lower");
    public static final ResourceKey<PlacedFeature> PLANTAGO =
            register("plantago");
    public static final ResourceKey<PlacedFeature> ACHILLEA_WHITE =
            register("achillea_white");
    public static final ResourceKey<PlacedFeature> ANAGALLIS_YELLOW =
            register("anagallis_yellow");
    public static final ResourceKey<PlacedFeature> ANTIRRHINUM =
            register("antirrhinum");
    public static final ResourceKey<PlacedFeature> CAMPANULA_BLUE =
            register("campanula_blue");
    public static final ResourceKey<PlacedFeature> CENTAUREA =
            register("centaurea");
    public static final ResourceKey<PlacedFeature> DIGITALIS_BLUE =
            register("digitalis_blue");
    public static final ResourceKey<PlacedFeature> DIGITALIS_YELLOW =
            register("digitalis_yellow");
    public static final ResourceKey<PlacedFeature> DOSERA =
            register("dosera");
    public static final ResourceKey<PlacedFeature> IRIS =
            register("iris");
    public static final ResourceKey<PlacedFeature> LEONTOPODIUM_WHITE =
            register("leontopodium_white");
    public static final ResourceKey<PlacedFeature> LEUCANTHEMUM_WHITE =
            register("leucanthemum_white");
    public static final ResourceKey<PlacedFeature> MUSHROOM_AMANITA_GREEN =
            register("mushroom_amanita_green");
    public static final ResourceKey<PlacedFeature> MUSHROOM_BOLETUS =
            register("mushroom_boletus");
    public static final ResourceKey<PlacedFeature> MUSHROOM_CANTHARELLUS =
            register("mushroom_cantharellus");
    public static final ResourceKey<PlacedFeature> MUSHROOM_GALERINA =
            register("mushroom_galerina");
    public static final ResourceKey<PlacedFeature> MUSHROOM_GYROMITRA =
            register("mushroom_gyromitra");
    public static final ResourceKey<PlacedFeature> MUSHROOM_MACROLEPIOTA =
            register("mushroom_macrolepiota");
    public static final ResourceKey<PlacedFeature> PAPVER_RED =
            register("papver_red");
    public static final ResourceKey<PlacedFeature> TRIFOLIUM_RED =
            register("trifolium_red");
    public static final ResourceKey<PlacedFeature> TRIFOLIUM_WHITE =
            register("trifolium_white");
    public static final ResourceKey<PlacedFeature> WILLOW =
            register("willow");
    public static final ResourceKey<PlacedFeature> FALLEN_WILLOW_TREE =
            register("fallen_willow_tree");

    /**
     * 添加放置生成
     * @param context  内容
     */
    public static void placedFeature(BootstrapContext<PlacedFeature> context) {
        registerOreFeatures(context, ORE_RUBY, ORE_RUBY_LOWER, ModConfiguredFeatureProvider.ORE_RUBY);
        registerOreFeatures(context, ORE_AMBER, ORE_AMBER_LOWER, ModConfiguredFeatureProvider.ORE_AMBER);
        registerHerbFeatures(context, PLANTAGO, ModConfiguredFeatureProvider.PLANTAGO);
        registerHerbFeatures(context, ACHILLEA_WHITE, ModConfiguredFeatureProvider.ACHILLEA_WHITE);
        registerHerbFeatures(context, ANAGALLIS_YELLOW, ModConfiguredFeatureProvider.ANAGALLIS_YELLOW);
        registerHerbFeatures(context, ANTIRRHINUM, ModConfiguredFeatureProvider.ANTIRRHINUM);
        registerHerbFeatures(context, CAMPANULA_BLUE, ModConfiguredFeatureProvider.CAMPANULA_BLUE);
        registerHerbFeatures(context, CENTAUREA, ModConfiguredFeatureProvider.CENTAUREA);
        registerHerbFeatures(context, DIGITALIS_BLUE, ModConfiguredFeatureProvider.DIGITALIS_BLUE);
        registerHerbFeatures(context, DIGITALIS_YELLOW, ModConfiguredFeatureProvider.DIGITALIS_YELLOW);
        registerHerbFeatures(context, DOSERA, ModConfiguredFeatureProvider.DOSERA);
        registerHerbFeatures(context, IRIS, ModConfiguredFeatureProvider.IRIS);
        registerHerbFeatures(context, LEONTOPODIUM_WHITE, ModConfiguredFeatureProvider.LEONTOPODIUM_WHITE);
        registerHerbFeatures(context, LEUCANTHEMUM_WHITE, ModConfiguredFeatureProvider.LEUCANTHEMUM_WHITE);
        registerHerbFeatures(context, MUSHROOM_AMANITA_GREEN, ModConfiguredFeatureProvider.MUSHROOM_AMANITA_GREEN);
        registerHerbFeatures(context, MUSHROOM_BOLETUS, ModConfiguredFeatureProvider.MUSHROOM_BOLETUS);
        registerHerbFeatures(context, MUSHROOM_CANTHARELLUS, ModConfiguredFeatureProvider.MUSHROOM_CANTHARELLUS);
        registerHerbFeatures(context, MUSHROOM_GALERINA, ModConfiguredFeatureProvider.MUSHROOM_GALERINA);
        registerHerbFeatures(context, MUSHROOM_GYROMITRA, ModConfiguredFeatureProvider.MUSHROOM_GYROMITRA);
        registerHerbFeatures(context, MUSHROOM_MACROLEPIOTA, ModConfiguredFeatureProvider.MUSHROOM_MACROLEPIOTA);
        registerHerbFeatures(context, PAPVER_RED, ModConfiguredFeatureProvider.PAPVER_RED);
        registerHerbFeatures(context, TRIFOLIUM_RED, ModConfiguredFeatureProvider.TRIFOLIUM_RED);
        registerHerbFeatures(context, TRIFOLIUM_WHITE, ModConfiguredFeatureProvider.TRIFOLIUM_WHITE);
        registerTree(context, WILLOW, FALLEN_WILLOW_TREE, ModConfiguredFeatureProvider.WILLOW, ModConfiguredFeatureProvider.FALLEN_WILLOW_TREE, ModBlocks.WILLOW_SAPLING.get());
    }

    /**
     * 注册树生成
     * @param context  内容
     * @param key 资源键
     * @param treeFeature 树生成
     * @param sapling 树苗
     */
    private static void registerTree(BootstrapContext<PlacedFeature> context, ResourceKey<PlacedFeature> key, ResourceKey<PlacedFeature> key2, ResourceKey<ConfiguredFeature<?, ?>> treeFeature, ResourceKey<ConfiguredFeature<?, ?>> fallenTreeFeature, Block sapling) {
        HolderGetter<ConfiguredFeature<?, ?>> holderGetter = context.lookup(Registries.CONFIGURED_FEATURE);
        Holder<ConfiguredFeature<?, ?>> holder = holderGetter.getOrThrow(treeFeature);
        Holder<ConfiguredFeature<?, ?>> holder2 = holderGetter.getOrThrow(fallenTreeFeature);
        PlacementUtils.register(context, key, holder, PlacementUtils.filteredByBlockSurvival(sapling));
        PlacementUtils.register(context, key2, holder2, PlacementUtils.filteredByBlockSurvival(sapling));
    }

    /**
     * 注册矿物生成
     * @param context 内容
     * @param key 资源键
     * @param oreFeature 矿物生成
     */
    public static void registerOreFeatures(BootstrapContext<PlacedFeature> context, ResourceKey<PlacedFeature> key, ResourceKey<PlacedFeature> key2, ResourceKey<ConfiguredFeature<?, ?>> oreFeature, boolean hasDeepSlateOre) {
        HolderGetter<ConfiguredFeature<?, ?>> holdergetter = context.lookup(Registries.CONFIGURED_FEATURE);
        Holder<ConfiguredFeature<?, ?>> holder = holdergetter.getOrThrow(oreFeature);
        PlacementUtils.register(context, key, holder, commonOrePlacement(4, HeightRangePlacement.uniform(VerticalAnchor.bottom(), VerticalAnchor.absolute(15))));
        if (hasDeepSlateOre) {
            PlacementUtils.register(context, key2, holder, commonOrePlacement(8, HeightRangePlacement.triangle(VerticalAnchor.aboveBottom(-32), VerticalAnchor.aboveBottom(32))));
        }
    }

    /**
     * 注册矿物生成
     * @param context  内容
     * @param key 键
     * @param oreFeature 矿物生成
     */
    public static void registerOreFeatures(BootstrapContext<PlacedFeature> context, ResourceKey<PlacedFeature> key, ResourceKey<ConfiguredFeature<?, ?>> oreFeature) {
        registerOreFeatures(context, key, null, oreFeature, false);
    }

    /**
     * 注册草药生成
     * @param context  内容
     * @param key 键
     * @param herbFeature 草药生成
     */
    private static void registerHerbFeatures(BootstrapContext<PlacedFeature> context, ResourceKey<PlacedFeature> key, ResourceKey<ConfiguredFeature<?, ?>> herbFeature) {
        HolderGetter<ConfiguredFeature<?, ?>> holdergetter = context.lookup(Registries.CONFIGURED_FEATURE);
        Holder<ConfiguredFeature<?, ?>> holder24 = holdergetter.getOrThrow(herbFeature);
        PlacementUtils.register(context, key, holder24, RarityFilter.onAverageOnceEvery(32), InSquarePlacement.spread(), PlacementUtils.HEIGHTMAP, BiomeFilter.biome());
    }

    /**
     * 注册矿物生成
     * @param context  内容
     * @param key 键
     * @param key2 键
     * @param oreFeature 矿物生成
     */
    public static void registerOreFeatures(BootstrapContext<PlacedFeature> context, ResourceKey<PlacedFeature> key, ResourceKey<PlacedFeature> key2, ResourceKey<ConfiguredFeature<?, ?>> oreFeature) {
        registerOreFeatures(context, key, key2, oreFeature, true);
    }

    /**
     * 注册新的资源键
     * @param name 名字
     * @return 资源键
     */
    private static ResourceKey<PlacedFeature> register(String name) {
        return ResourceKey.create(Registries.PLACED_FEATURE, Helpers.identifier(name));
    }

    /**
     * 创建矿物生成
     * @param countPlacement 放置数量
     * @param heightRange 高度
     * @return 矿物生成
     */
    private static List<PlacementModifier> orePlacement(PlacementModifier countPlacement, PlacementModifier heightRange) {
        return List.of(countPlacement, InSquarePlacement.spread(), heightRange, BiomeFilter.biome());
    }

    /**
     * 创建通用矿物生成
     * @param count 放置数量
     * @param heightRange 高度
     * @return 通用矿物生成
     */
    private static List<PlacementModifier> commonOrePlacement(int count, PlacementModifier heightRange) {
        return orePlacement(CountPlacement.of(count), heightRange);
    }
}
